from __future__ import annotations

from typing import List, Optional
import random

from .models import (
    KnowledgePoint,
    GenerationConfig,
    Question,
    GenerationOutput,
    GenerationMetadata,
)
from .quality import QualityValidator
from .similarity import deduplicate
from .rule_generator import RuleBasedQuestionGenerator


class QuestionGenerator:
    def __init__(self, model_config: Optional[dict] = None, seed: Optional[int] = None):
        self.model_config = model_config or {}
        self.quality_validator = QualityValidator()
        self.generator = RuleBasedQuestionGenerator()
        self.random_state = random.Random(seed)

    def generate_questions(self, knowledge_point: dict, config: dict) -> dict:
        kp = KnowledgePoint(
            name=knowledge_point["name"],
            description=knowledge_point["description"],
            difficulty_level=knowledge_point["difficulty_level"],
            cognitive_level=knowledge_point["cognitive_level"],
        )
        kp.validate()

        cfg = GenerationConfig(
            question_type=config["question_type"],
            difficulty=str(config["difficulty"]),
            count=int(config["count"]),
            language=config.get("language", "中文"),
        )
        # format_spec fields
        fmt = config.get("format_spec", {})
        cfg.format_spec.include_explanation = bool(fmt.get("include_explanation", True))
        cfg.format_spec.options_count = int(fmt.get("options_count", 4))
        cfg.validate()

        raw_questions: List[Question] = []
        for _ in range(cfg.count):
            q = self.generator.generate_one(kp, cfg, self.random_state)
            # difficulty adjustment hook if needed
            target_diff = cfg.normalized_difficulty()
            if q.difficulty != target_diff:
                q.difficulty = max(1, min(10, q.difficulty))
            raw_questions.append(q)

        # quality validation
        validated: List[Question] = []
        for q in raw_questions:
            res = self.quality_validator.validate(q, kp)
            q.quality_score = res.score
            if res.passed:
                validated.append(q)

        # deduplication
        deduped, _ = deduplicate(validated, threshold=0.9)
        valid_count = len(deduped)
        if valid_count:
            total_quality_dedup = sum((q.quality_score or 0.0) for q in deduped)
            avg_quality = round(total_quality_dedup / valid_count, 4)
        else:
            avg_quality = 0.0

        metadata = GenerationMetadata(
            generated_count=len(raw_questions),
            valid_count=valid_count,
            average_quality=avg_quality,
            generation_time=GenerationMetadata.now_iso(),
        )
        output = GenerationOutput(questions=deduped, metadata=metadata)
        return output.to_dict()

    def validate_question(self, question: dict, knowledge_point: dict) -> dict:
        q = Question(
            id=question.get("id") or Question.new_id(),
            type=question["type"],
            stem=question["stem"],
            options=question.get("options"),
            correct_answer=question.get("correct_answer"),
            explanation=question.get("explanation"),
            difficulty=int(question.get("difficulty", 5)),
            cognitive_level=question.get("cognitive_level", "理解"),
            knowledge_points=question.get("knowledge_points", []),
            quality_score=question.get("quality_score"),
        )
        kp = KnowledgePoint(
            name=knowledge_point["name"],
            description=knowledge_point["description"],
            difficulty_level=knowledge_point["difficulty_level"],
            cognitive_level=knowledge_point["cognitive_level"],
        )
        kp.validate()
        res = self.quality_validator.validate(q, kp)
        return {"passed": res.passed, "score": res.score, "messages": res.messages}

    def adjust_difficulty(self, question: dict, target_difficulty: int) -> dict:
        q = Question(
            id=question.get("id") or Question.new_id(),
            type=question["type"],
            stem=question["stem"],
            options=question.get("options"),
            correct_answer=question.get("correct_answer"),
            explanation=question.get("explanation"),
            difficulty=int(question.get("difficulty", 5)),
            cognitive_level=question.get("cognitive_level", "理解"),
            knowledge_points=question.get("knowledge_points", []),
            quality_score=question.get("quality_score"),
        )
        q.difficulty = max(1, min(10, int(target_difficulty)))
        return q.to_dict()